package com.example.client8081.controller;


import com.example.proto.ArithGrpc;
import com.example.proto.Int;
import com.example.proto.Param;
import com.example.proto.Quotient;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.Integer;
import java.io.IOException;


@RestController
@RequestMapping("/arith")
public class ArithController {
    //~ Static fields/constants/initializer

    private static final Logger log = LoggerFactory.getLogger(ArithController.class);

    //~ Instance fields

    @Value("${rpc.host}")
    private String rpcHost;
    @Value("${rpc.port}")
    private int rpcPort;

    private ManagedChannel channel;
    private final ArithGrpc.ArithBlockingStub arithBlockingStub;
    private final ArithGrpc.ArithStub arithStub;

    public ArithController() {
        // 确保使用正确的服务器地址和端口
        this.channel = ManagedChannelBuilder.forAddress("localhost", 8080)
                .usePlaintext()
                .build();
        this.arithBlockingStub = ArithGrpc.newBlockingStub(channel);
        this.arithStub = ArithGrpc.newStub(channel);
    }

    @PostConstruct
    public void init() {
        connectToRpc();
    }

    // http GET ":8081/arith/m?a=5&b=3"
    @GetMapping("/m")
    public int multiply(Integer a, Integer b) {

        log.info("Multiplying a " + a + " and b " + b);
        // output: Multiplying a 5 and b 3
        // 阻塞请求，同步调用
        ArithGrpc.ArithBlockingStub arithBlockingStub = ArithGrpc.newBlockingStub(channel);
        Int ret = arithBlockingStub.multiply(Param.newBuilder().setA(a).setB(b).build());
        int v = ret.getRet();
        log.info("received: {}", v);
        return v;
    }

    @GetMapping("/d")
    public void divide(Integer a, Integer b, HttpServletResponse resp) {
            Param p = Param.newBuilder().setA(a).setB(b).build();
        // 异步调用
        ArithGrpc.ArithStub arithStub = ArithGrpc.newStub(channel);
        arithStub.divide(p, new StreamObserver<Quotient>() {
            @Override
            public void onNext(Quotient quotient) {
                log.info("{} divide {} success: quotient = {}, remain = {}", a, b, quotient.getQuo(), quotient.getRem());
                try {
                    resp.getWriter().write(String.format("a / b = %d, mod = %d", quotient.getQuo(), quotient.getRem()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onError(Throwable throwable) {
                log.error("{} divide {} error: {}", a, b, throwable);
            }

            @Override
            public void onCompleted() {
                log.info("{} divide {} completed", a, b);
            }
        });
    }


    public void connectToRpc() {
        log.info("Connecting to rpc host: {}", rpcHost);
        log.info("Connecting to rpc port: {}", rpcPort);
        channel = ManagedChannelBuilder.forAddress(rpcHost, rpcPort).usePlaintext().build();
        if (!channel.isShutdown() || !channel.isTerminated()) {
            log.info("connect to rpc server, host: {}, port: {}", rpcHost, rpcPort);
        }
    }
}
